/*---------begin changed by wangwei--------------*/
//the whole file is changed, the original file is named as hostutil_old.c
/*---------end changed---------------------------*/
/* $Header: hostutil.c,v 2.3 02/07/26 12:32:14 przybyls Exp $ */

/***********************************************************************/
/*                                                                     */
/*                  Copyright Hewlett-Packard Co. 1991                 */
/*                                                                     */
/***********************************************************************/

/***********************************************************************/
/* MODULE NAME: hostutil.c                                             */
/* ============                                                        */
/*                                                                     */
/* Author:  Bob Cook                                                   */
/*                                                                     */
/* MODULE PURPOSE: This module contains the utilities used by the      */
/*                 by the command processor.                           */
/*                                                                     */
/*                                                                     */
/***********************************************************************/

/*
 */

/*****************************/
/*   GLOBAL INCLUDE FILES    */
/*****************************/

#include <typedefs.h>
#include <stddef.h>
#include <error.h>
#include <i_op.h>
#include <iomap.h>
#include <mio.h>
#include <cmd_set.h>
#include <method.h>
#include <hostutil.h>
#include <wkfutil.h>
#include <cmdproc.h>
#include <p_wkfile.h>
#include <wkfile.h>
#include <messages.h>
#include <ramps.h>
#include <zone_config.h>
#include <zone_status.h>
#include <status.h>
#include <display.h>



/*****************************/
/*   LOCAL INCLUDE FILES     */
/*****************************/



/*****************************/
/*   GLOBAL VARIABLES        */
/*****************************/

U_INT16  Host_Error_Count[5];
HOST_ERR_RECORD_TYPE Host_Err_Log[5][20];

/* internal buffer used to direct output to an IQ location instead of a port */
INTERNAL_BUFFER_TYPE  Internal_Buffer;


/*****************************/
/*   EXTERNAL VARIABLES      */
/*****************************/

extern CMD_QUEUE_TYPE  CC_Cmd_Q;
extern CMD_QUEUE_TYPE  Q0_Cmd_Q;
extern CMD_QUEUE_TYPE  Q1_Cmd_Q;
extern CMD_QUEUE_TYPE  Q2_Cmd_Q;
extern CMD_QUEUE_TYPE  Q3_Cmd_Q;
extern CMD_QUEUE_TYPE  Free_Cmd_Q;
extern QUEUE_TYPE   Wr_Free_Q;
extern QUEUE_TYPE   Wr_Output_Q[NUM_PORTS];
extern  QUEUE_TYPE  MIO_Rd_Free_Q;
extern pthread_mutex_t Cmd_Q_Mut;

/*****************************/
/*   LOCAL DEFINES           */
/*****************************/

/* if BC_DEBUG is defined debug buffers are created and statics become global */
#define BC_DEBUG

/* when debugging make variables global for emulator testing */
#ifdef BC_DEBUG
#   define SCOPE
#else
#   define  SCOPE  static
#endif


/*****************************/
/*   STATIC VARIABLES        */
/*****************************/



/*****************************/
/*   MACROS                  */
/*****************************/



/*****************************/
/*   IMPLEMENT SECTION       */
/*****************************/



/***********************************************************************/
/* FUNCTION: StrLen                                                    */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: Determine length of string, given a pointer to beginning   */
/*          of the string.                                             */
/*                                                                     */
/* RETURNED VALUE: none                                                */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*                                                                     */
/* CALLS:                                                              */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/* WARNINGS:                                                           */
/*                                                                     */
/***********************************************************************/

INT16 StrLen(BIT8 *str)
{
INT16 n;

   n = 0;
   while(*str++)
   {
      n++;
   }
   return  n;
}



/***********************************************************************/
/* FUNCTION: StrCat                                                    */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: concatenate string str2 to end of string str1              */
/*                                                                     */
/* RETURNED VALUE: none                                                */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*                                                                     */
/* CALLS:                                                              */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/* WARNINGS:                                                           */
/*                                                                     */
/***********************************************************************/

void StrCat(BIT8 *str1,BIT8 *str2)
{
   while(*str1)
   str1++;
   do
   {
      *str1++ = *str2;
   } while(*str2++);
   return;
}


/***********************************************************************/
/* FUNCTION: StrNCmp                                                   */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: compare at most n characters of string str1 to string str2 */
/*                                                                     */
/* RETURNED VALUE: return     1 if strings are the same                */
/*                            0 if strings are the different           */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*                                                                     */
/* CALLS:                                                              */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/* WARNINGS:                                                           */
/*                                                                     */
/***********************************************************************/

INT16 StrNCmp(BIT8 *str1,BIT8 *str2,INT16 n)
{
   do{
      if(*str1 != *str2)
      {
         return 0;
      }
      str1++;
      str2++;
      n--;
   } while(n);
   return  1;
}


/***********************************************************************/
/* FUNCTION: StrNCpy                                                   */
/* ========                                                            */
/*                                                                     */
/* PURPOSE:  copy at most n characters of string from_str to to_str    */
/*                                                                     */
/* RETURNED VALUE: return to_str                                       */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*                                                                     */
/* CALLS:                                                              */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/* WARNINGS:                                                           */
/*                                                                     */
/***********************************************************************/

void StrNCpy(BIT8 *to_str,BIT8 *from_str,INT16 n)
{
   do
   {
      *to_str++ = *from_str++;
   } while(--n && *from_str);
   *to_str = 0x0;
   return;
}



/***********************************************************************/
/* FUNCTION: RecursiveIntToDec                                         */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: Recursive part of IntToDec. Makes IntToDec re-entrant.     */
/*            Should only be used by IntToDec.                         */
/*                                                                     */
/* RETURNED VALUE: length of string                                    */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                Should only be called by IntToDec.                   */
/*                                                                     */
/* WARNINGS:                                                           */
/*                                                                     */
/***********************************************************************/

U_INT16 RecursiveIntToDec(INT32 dec,BIT8 *str,U_INT16  *p_len)
{
U_INT16 neg;


   *p_len = 0;
   neg = 0;
   if( dec < 0 )
   {
      dec = -dec;
      *str++ = '-';
      neg = 1;
   }

   if( dec >= 10)                  /* first recurse for each digit */
   {
      *p_len = RecursiveIntToDec(dec/10, str,p_len);
      dec %= 10;                   /* process each digit by modulo */
   }
   *(str+(*p_len)) = '0' + (char)dec;     /* output as character */
   return  ((*p_len)+neg+1);
}


/***********************************************************************/
/* END FUNCTION: IntToDec                                              */
/***********************************************************************/

/***********************************************************************/
/* FUNCTION: IntToDec                                                  */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: Convert 32 bit signed int to ASCII decimal                 */
/*                                                                     */
/* RETURNED VALUE: length of string                                    */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*                                                                     */
/* CALLS:                                                              */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/* WARNINGS:                                                           */
/*                                                                     */
/***********************************************************************/


U_INT16 IntToDec(INT32 dec,BIT8 *str)
{
U_INT16 len;
U_INT16 neg;


   len = 0;
   neg = 0;
   if( dec < 0 )
   {
      dec = -dec;
      *str++ = '-';
      neg = 1;
   }

   if( dec >= 10)                  /* first recurse for each digit */
   {
      len = RecursiveIntToDec(dec/10, str, &len);
      dec %= 10;                   /* process each digit by modulo */
   }
   *(str+len) = '0' + (char)dec;     /* output as character */
   return  (len+neg+1);
}


/***********************************************************************/
/* END FUNCTION: IntToDec                                              */
/***********************************************************************/




/***********************************************************************/
/* FUNCTION: IntToDecFilled                                            */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: Convert 32 bit signed int to ASCII decimal                 */
/*                                                                     */
/* RETURNED VALUE: length of string                                    */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*                                                                     */
/* CALLS:                                                              */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/* WARNINGS:                                                           */
/*                                                                     */
/***********************************************************************/

#if 0
/* Duplicate function in dt_cmds.c */
U_INT16 IntToDecFilled( INT32 dec, BIT8 *str, INT16 size )
{
   INT32   value;
   INT16   i;

   for (i=size-1; i>=0; i--)
   {
      value = dec % 10;                 /* get the last digit */
      dec /= 10;                        /* process each digit by division */
      *(str+i) = '0' + (char)value;     /* output as character */
   }
   return  (size);

}

#endif

/***********************************************************************/
/* END FUNCTION: IntToDecFilled                                        */
/***********************************************************************/

/***********************************************************************/
/* FUNCTION: Negate48                                                  */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: Reverse the sign of a number.                              */
/*                                                                     */
/* RETURNED VALUE: None                                                */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/* WARNINGS:                                                           */
/*                                                                     */
/***********************************************************************/

void Negate48(INT32 *num_hi,INT16 *num_lo)
{
/* change sign of 48 bit number: num = 0 - num */
(void) num_hi;
(void) num_lo;

#ifndef mccabe
#pragma ASM
   MOVEA.L (S_num_hi,A6),A1
   MOVEA.L (S_num_lo,A6),A0
   NEG.W   (A0)              ; negate lower 16 bits
   NEGX.L  (A1)              ; negate upper 32 bits
#pragma END_ASM
#endif

printf("Negate48\n");
}
/***********************************************************************/
/* END FUNCTION: Negate48                                              */
/***********************************************************************/

/***********************************************************************/
/* FUNCTION: RecursiveIntToDec48                                       */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: Used by IntToDec48 to convert 48 bit signed int to         */
/*          ASCII decimal. Function makes IntToDec48 re-entrant.       */
/*                                                                     */
/* RETURNED VALUE: length of string                                    */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*                                                                     */
/* LIMITATIONS:   Intended to be called by IntToDec48 only.            */
/*                                                                     */
/* WARNINGS:                                                           */
/*                                                                     */
/***********************************************************************/

U_INT16 RecursiveIntToDec48(NUM_TYPE num,BIT8 *str,U_INT16 *p_len)
{

   U_INT16    neg;
   U_INT32    quot_hi;
   U_INT32    quot_lo;
   U_INT32    rem_hi;
   U_INT32    rem_hi_shift;
   NUM_TYPE   quot;
   INT16      rem;

   *p_len = 0;
   neg = 0;

   /* check if less than zero */
   if( num.dig_data.hi_long < 0 )
   {
      Negate48(&num.dig_data.hi_long, &num.dig_data.lo_word);
      *str++ = '-';
      neg = 1;
   }

   /* if number is one digit, done recursion; output digit */
   if( (num.dig_data.hi_long == 0) && ((U_INT16)num.dig_data.lo_word < 10) )
   {
      /* one digit */
      rem = num.dig_data.lo_word;
   }
   else
   {
      /* multiple digits */
      /* check if 32 bit math is possible */
      /*
       * NOTE, cast to U_INT so numbers are not sign extended and the
       *    correct divide instruction is used
       */
      if( (num.dig_data.hi_long & 0xFFFF8000) != 0 )
      {
         /* use 48 bit math */
         quot_hi = (U_INT32)num.dig_data.hi_long / 10;
         rem_hi = (U_INT32)num.dig_data.hi_long % 10;

         rem_hi_shift = rem_hi << 16;

         quot_lo = (rem_hi_shift + (U_INT16)num.dig_data.lo_word)/10;
         quot.dig_data.hi_long = (quot_lo >> 16) + quot_hi;
         quot.dig_data.lo_word = (U_INT16)quot_lo;
         rem = (rem_hi_shift + (U_INT16)num.dig_data.lo_word) % 10;

      }
      else
      {
         /* use 32 bit math */

         quot.int48.hi_word = 0;
         quot.int48.lo_long = (U_INT32)num.int48.lo_long / 10;
         rem = (U_INT32)num.int48.lo_long % 10;
      }
      /* first recurse for each digit */
      *p_len = RecursiveIntToDec48(quot,str,p_len);
   }
   *(str+(*p_len)) = '0' + (char)rem;     /* output one character */
   return  ((*p_len)+neg+1);
}


/***********************************************************************/
/* END FUNCTION: RecursiveIntToDec48                                   */
/***********************************************************************/


/***********************************************************************/
/* FUNCTION: IntToDec48                                                */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: Convert 48 bit signed int to ASCII decimal                 */
/*                                                                     */
/* RETURNED VALUE: length of string                                    */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*                                                                     */
/* CALLS:                                                              */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/* WARNINGS:                                                           */
/*                                                                     */
/***********************************************************************/

/*
 *       N      W*2^16 + X
 *      --- =  -----------  = (W/10)*2^16 + X/10
 *       10       10
 *
 *
 *             = (Q + R/10)*2^16 +X/10  =  Q*2^16 + (R*2^16 + X)/10
 *
 *      Quotient  = Q*2^16 + Q'
 *      Remainder = R'
 *
 *    where    N is original number
 *             W is upper 32 bits of point
 *             X is lower 16 bits of point
 *             Q is quotient of W/10
 *             R is remainder of W/10
 *             Q' is quotient of (R*2^16+X)/10
 *             R' is remainder of (R*2^16+X)/10
 */

U_INT16 IntToDec48(NUM_TYPE num,BIT8 *str)
{

   U_INT16    len;
   U_INT16    neg;
   U_INT32    quot_hi;
   U_INT32    quot_lo;
   U_INT32    rem_hi;
   U_INT32    rem_hi_shift;
   NUM_TYPE   quot;
   INT16      rem;

   len = 0;
   neg = 0;
   /* check if less than zero */
   if( num.dig_data.hi_long < 0 )
   {
      Negate48(&num.dig_data.hi_long, &num.dig_data.lo_word);
      *str++ = '-';
      neg = 1;
   }

   /* if number is one digit, done recursion; output digit */
   if( (num.dig_data.hi_long == 0) && ((U_INT16)num.dig_data.lo_word < 10) )
   {
      /* one digit */
      rem = num.dig_data.lo_word;
   }
   else
   {
      /* multiple digits */
      /* check if 32 bit math is possible */
      /*
       * NOTE, cast to U_INT so numbers are not sign extended and the
       *    correct divide instruction is used
       */
      if( (num.dig_data.hi_long & 0xFFFF8000) != 0 )
      {
         /* use 48 bit math */
         quot_hi = (U_INT32)num.dig_data.hi_long / 10;
         rem_hi = (U_INT32)num.dig_data.hi_long % 10;

         rem_hi_shift = rem_hi << 16;

         quot_lo = (rem_hi_shift + (U_INT16)num.dig_data.lo_word)/10;
         quot.dig_data.hi_long = (quot_lo >> 16) + quot_hi;
         quot.dig_data.lo_word = (U_INT16)quot_lo;
         rem = (rem_hi_shift + (U_INT16)num.dig_data.lo_word) % 10;

      }
      else
      {
         /* use 32 bit math */

         quot.int48.hi_word = 0;
         quot.int48.lo_long = (U_INT32)num.int48.lo_long / 10;
         rem = (U_INT32)num.int48.lo_long % 10;
      }
      /* first recurse for each digit */
      len = RecursiveIntToDec48(quot,str,&len);
   }
   *(str+len) = '0' + (char)rem;     /* output one character */
   return  (len+neg+1);
}

/***********************************************************************/
/* END FUNCTION: IntToDec48                                            */
/***********************************************************************/





/***********************************************************************/
/* FUNCTION: DecToInt                                                  */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: Convert ASCII String to 32 bit signed int                  */
/*                                                                     */
/* RETURNED VALUE: UI_ERR code                                         */
/*                                                                     */
/* EXAMPLE:                                                            */
/*                                                                     */
/*       ASCII NUMBER | Signif digits | Binary Integer Created         */
/*       ------------ | ------------- | ----------------------         */
/*         123.45678  |      3        |      123456                    */
/*         123.4      |      3        |      123400                    */
/*         1          |      3        |       1000                     */
/*                                                                     */
/*                                                                     */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*    If Ascii string represents a number which exceeds a signed       */
/*      32 bit number DecToInt will quit and return PARAM_TOO_LARGE.   */
/*      Calling program should check if error is returned.             */
/*                                                                     */
/* WARNINGS:                                                           */
/*                                                                     */
/***********************************************************************/

UI_ERR  DecToInt(BIT8 *str, U_INT16 signif_dig, INT32 *value)

{
U_INT16      dig;
U_INT16  neg_num;

    *value = 0;
    dig = 0;

    /* check for negative number */
    if(*str == '-')
    {
       neg_num = TRUE;
       str++;
    }
    else
    {
       neg_num = FALSE;
    }

    /* check for number */
    if ( StrLen(str) == 0 )
    {
       return MISSING_PARAM;
    }

   if( neg_num == FALSE )
   {
   /* POSITIVE NUMBER */
      while( ISDIGIT(*str) )
      {
         *value *= 10;
         *value += *str++ - '0';

         /* check for overflow */
         if( *value < 0 )
         {
             return PARAM_TOO_LARGE;
         }
      }
      if (*str == '.')
      {
          str++;
          while( (dig < signif_dig) && ISDIGIT(*str) )
          {
             *value *= 10;
             *value += *str++ - '0';
             /* check for overflow */
             if( *value < 0 )
             {
                return PARAM_TOO_LARGE;
             }
             dig++;
          }

      }
      /* add number of significant digits for this parameter */
      for ( ; (dig < signif_dig) ; dig++ )
      {
          *value *= 10;
          /* check for overflow */
          if( *value < 0 )
          {
             return PARAM_TOO_LARGE;
          }
      }
   }
   else
   {
   /* NEGITIVE NUMBER */
      while( ISDIGIT(*str) )
      {
         *value *= 10;
         *value -= *str++ - '0';
         /* check for overflow */
         if( *value > 0)
         {
             return PARAM_TOO_LARGE;
         }
      }
      if (*str == '.')
      {
          str++;
          while( dig < signif_dig && ISDIGIT(*str) )
          {
             *value *= 10;
             *value -= *str++ - '0';
             /* check for overflow */
             if( *value > 0 )
             {
                return PARAM_TOO_LARGE;
             }
             dig++;
          }

      }
      /* add number of significant digits for this parameter */
      for ( ; (dig < signif_dig) ; dig++ )
      {
          *value *= 10;
          /* check for overflow */
          if( *value > 0 )
          {
             return PARAM_TOO_LARGE;
          }
      }

   }
   return OK;
}
/***********************************************************************/
/* END FUNCTION: DecToInt                                              */
/***********************************************************************/


/***********************************************************************/
/* FUNCTION: HexToInt                                                  */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: Convert hexadecimal ASCII String to 32 bit unsigned int    */
/*                                                                     */
/* RETURNED VALUE: 32 bit unsigned int                                 */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*                                                                     */
/* CALLS:                                                              */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*    This routine handles only positive hexadecimal values.           */
/*                                                                     */
/* WARNINGS:                                                           */
/*                                                                     */
/***********************************************************************/
UI_ERR HexToInt( BIT8 *str, U_INT32 *value )
{

   INT16 length;

   *value = 0;

   length = StrLen( str );

   if ( length > 8 )
   {
      return( PARAM_TOO_LARGE );
   }

   if ( length == 0 )
   {
      return( MISSING_PARAM );
   }


   while ( length )
   {
      /* First convert possible upper-case character to lower-case */
      if ( IS_UPPER( *str ) )
      {
         *str += 'a' - 'A';
      }

      if ( IS_HEX_DIGIT(*str) )
      {
         *value *= 16;

         if ( ISDIGIT(*str) )
         {
            *value += *str - '0';
         }
         else
         {
            *value += *str - 'a' + 10;
         }

         str++;
         length--;
      }
      else
      {
         return( INVALID_PARAM );
      }
   }

   return( OK );
}

/***********************************************************************/
/* END FUNCTION: HexToInt                                              */
/***********************************************************************/


/***********************************************************************/
/* FUNCTION: GetAWordParam                                             */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: number coversion, hex if preceeded by '0x',  dec otherwise */
/*                                                                     */
/* RETURNED VALUE: 16 bit unsigned int                                 */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*                                                                     */
/* CALLS:                                                              */
/*                                                                     */
/* LIMITATIONS: value undefined if conversion fails.                   */
/*                                                                     */
/* WARNINGS:                                                           */
/*                                                                     */
/***********************************************************************/

UI_ERR GetAWordParam( CMD_TYPE *p_cmd, U_INT16 num, U_INT16 *value )
{

    UI_ERR  error;
    U_INT32 temp;

    error = OK;

    if ( StrLen( &p_cmd->parms[p_cmd->parmv[num]] ) != 0 )
    {
         if (( StrLen ( &p_cmd->parms[p_cmd->parmv[num]] ) > 2 ) &&
            (( (&p_cmd->parms[p_cmd->parmv[num]])[0] == '0' ) &&
            ( (&p_cmd->parms[p_cmd->parmv[num]])[1] == 'x' ) ) )
         {
              error=HexToInt( &(&p_cmd->parms[p_cmd->parmv[num]])[2], (U_INT32 *) &temp );
         }
         else
         {
              error=DecToInt( &p_cmd->parms[p_cmd->parmv[num]], 0, (INT32 *) &temp );
         }

         if (( error == OK ) && ( temp > 65535 ))
         {
              error = INVALID_PARAM;
         }

         if ( error == OK )
         {
              *value = temp;
         }
    }
    else
    {
         error = INVALID_PARAM;
    }

    return error;
}

/***********************************************************************/
/* END FUNCTION: GetAWordParam                                         */
/***********************************************************************/




/***********************************************************************/
/* FUNCTION: PutIntParam                                               */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: Convert a signed 32 bit number to an ASCII decimal number  */
/*          and put in response buffer.                                */
/*          Handles the full signed 32 bit range.                      */
/*                                                                     */
/* RETURNED VALUE: Number of characters put in the response buffer.    */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*                                                                     */
/* FILE SCOPE STATICS USED:                                            */
/*                                                                     */
/*                                                                     */
/*                                                                     */
/***********************************************************************/

U_INT16 PutIntParam(INT32 value, BIT8   *p_resp_parm, U_INT16 signif_dig)
{
U_INT16  length;
U_INT16  index;
U_INT16   neg_num;

   /* work with a positive number and add sign last to simplify algorithm */
   /*    Since numbers may be between +2147483647 and -2147483648 , need  */
   /*    to handle the most negitive number seperately. */
   if ( value <0 )
   {
      neg_num = TRUE;
      if( (U_INT32)value == 0x80000000 ) /* -2147483648 */
      {
        length = 10;
        (void)PutAsciiParam((BIT8 *)"2147483648",p_resp_parm);
      }
      else
      {
         value = -value;
         length = IntToDec(value,p_resp_parm);
      }
   }
   else
   {
      neg_num = FALSE;
      length = IntToDec(value,p_resp_parm);
   }

   if ( signif_dig > 0 && length > 0 )
   {
      if ( length <= signif_dig )
      {
         for(  ; length <= (signif_dig) ; length++ )
         {
            for( index = length ; index > 0 ; index-- )
            {
               *(p_resp_parm + index) = *(p_resp_parm + index - 1);
            }
            *p_resp_parm = '0';
         }
      }
      for( index = length ; (length - index) < signif_dig ; index--)
      {
         *(p_resp_parm + index) = *(p_resp_parm + index - 1);
      }
      *(p_resp_parm + index) = '.';
      length++;
   }
   if( neg_num == TRUE )
   {
      for( index = length ; index > 0 ; index-- )
      {
         *(p_resp_parm + index) = *(p_resp_parm + index - 1);
      }
      *p_resp_parm = '-';
      length++;
   }
   return  length;
}

/***********************************************************************/
/* END FUNCTION: PutIntParam                                           */
/***********************************************************************/



/***********************************************************************/
/* FUNCTION: PutHexParam                                               */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: Convert a unsigned 32 bit number to an ASCII hexadecimal   */
/*          number and put in response buffer.                         */
/*          No leading zeros or spaces are added.                      */
/*                                                                     */
/* RETURNED VALUE: Number of hex characters put in response buffer,    */
/*                 may be from 1 to 8 characters.                      */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*                                                                     */
/* FILE SCOPE STATICS USED:                                            */
/*                                                                     */
/*                                                                     */
/* CALLS:                                                              */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/* WARNINGS:                                                           */
/*                                                                     */
/*                                                                     */
/***********************************************************************/
U_INT16 PutHexParam(U_INT32 value, BIT8  *p_resp_parm)
{
U_INT32 nibble;
U_INT16 i, leading_zero, length;

   length = 0;
   leading_zero = TRUE;

   /* hex format the number */
   /* max 32-bit value needs 8 nibbles for representation */
   for (i = 0; i < 8; i++)
   {
      /* extract a nibble (4-bits) */
      nibble = (value & 0xf0000000) >> 28;
      value = value << 4;

      /*  stop removing leading zeros with the first non-zero nibble */
      if (nibble != 0)
      {
            leading_zero = FALSE;
      }

      if (leading_zero == FALSE)
      {
         /* format significant nibbles */
         *(p_resp_parm+length) = (nibble < 10) ? '0' + nibble : ('A' - 10) + nibble;
         length++;
      }
   }

   if (leading_zero == TRUE)
   {
      /* no non zero value found, must be zero */
      *p_resp_parm = '0';
      length = 1;
   }

   return length;
}

/***********************************************************************/
/* END FUNCTION: PutHexParam                                           */
/***********************************************************************/


/***********************************************************************/
/* FUNCTION: PutAsciiParam                                               */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: Put an ASCII string in the response buffer.                */
/*                                                                     */
/* RETURNED VALUE: Number of characters put in the response buffer.    */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*                                                                     */
/* FILE SCOPE STATICS USED:                                            */
/*                                                                     */
/*                                                                     */
/* CALLS:                                                              */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/* WARNINGS:                                                           */
/*                                                                     */
/*                                                                     */
/***********************************************************************/

U_INT16 PutAsciiParam(BIT8  *from_str, BIT8   *to_loc)
{
U_INT16   len;
U_INT16   i;

   len = StrLen(from_str);
   for ( i = 0; i < len ; i++ )
   {
      *to_loc++ = *from_str++;
   }
   return  len;

}

/***********************************************************************/
/* END FUNCTION: PutAsciiParam                                         */
/***********************************************************************/


/***********************************************************************/
/* FUNCTION: CmdErrorHandler                                           */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: Handles error from datacomm cmd processor.                 */
/*                                                                     */
/* RETURNED VALUE: none                                                */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*                                                                     */
/* FILE SCOPE STATICS USED:                                            */
/*                                                                     */
/*                                                                     */
/* CALLS:                                                              */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/* WARNINGS:                                                           */
/*                                                                     */
/*                                                                     */
/***********************************************************************/

/*
 * The CmdErrorHandler is used to log errors generated by commands
 * from the host port.  The type of errors are given in error.h as UI_ERR.
 * The function will log the dsap, ssap, and op_code of the command
 * along with the parameter that caused the error and the error.
 * Up to 20 errors may be logged.  After 20 errors are logged, new
 * ones are ignored.
 * The error log may be read by the host.  Reading the error log will
 * remove the entries.
 */

void CmdErrorHandler(CMD_TYPE *p_cmd,U_INT16 param,UI_ERR error)
{
U_INT16 len;
U_INT16 chan;

   /* FPD backward compatibility KLUDGE: Rev 4.02 and lower still */
   /* emit commands to the FPD_AUX heated zone.                   */
   if ( error == IGNORE_SETPTS ) return;

   chan = p_cmd->comm_port;

   if (chan > 4) return;    /* protect from INTERNAL_BUFFER doing logging */

   if( !(error == OK || error == NO_INSTR) && (Host_Error_Count[chan] < 20) )
   {
      /* log dsap, ssap, and opcode as received plus error code */
      Copy2(p_cmd->dsap.char_dsap, Host_Err_Log[chan][Host_Error_Count[chan]].dsap);
      Copy2(p_cmd->ssap.char_ssap, Host_Err_Log[chan][Host_Error_Count[chan]].ssap);
      Copy2(p_cmd->opcode.char_op, Host_Err_Log[chan][Host_Error_Count[chan]].opcode);
      Host_Err_Log[chan][Host_Error_Count[chan]].separator1[0] = ' ';
      /* add P for parameter */
      Host_Err_Log[chan][Host_Error_Count[chan]].separator1[1] = 'P';
      /* add leading space */
      Host_Err_Log[chan][Host_Error_Count[chan]].param[1] = ' ';
      (void)IntToDec( (INT32)param,Host_Err_Log[chan][Host_Error_Count[chan]].param);
      Host_Err_Log[chan][Host_Error_Count[chan]].separator2[0] = ' ';
      /* add E for error number */
      Host_Err_Log[chan][Host_Error_Count[chan]].separator2[1] = 'E';
      len = IntToDec( (INT32)error,Host_Err_Log[chan][Host_Error_Count[chan]].error);
      /* add end of string indication */
      Host_Err_Log[chan][Host_Error_Count[chan]].error[len] = 0;


      Host_Error_Count[chan]++;
   }

}

/***********************************************************************/
/* END FUNCTION: CmdErrorHandler                                       */
/***********************************************************************/



/***********************************************************************/
/* FUNCTION: GetRespBuf                                                */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: Gets a response buffer from the queue of free "write       */
/*          buffers".                                                  */
/*                                                                     */
/* RETURNED VALUE: none                                                */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*                                                                     */
/* FILE SCOPE STATICS USED:                                            */
/*                                                                     */
/*                                                                     */
/* CALLS:                                                              */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/* WARNINGS:                                                           */
/*                                                                     */
/*                                                                     */
/***********************************************************************/

MIO_HDR_TYPE  *GetRespBuf(void)

{
   MIO_HDR_TYPE  *p_resp_packet;
   /* transfer packet to driver */
   GetPacket(p_resp_packet, Wr_Free_Q);  /* CRITICAL REGION */
   return (p_resp_packet);
}



/***********************************************************************/
/* FUNCTION: SetUpRespHdr                                              */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: Initializes the header portion of the response buffer.     */
/*           <dest><source><opcode><space>                             */
/*                                                                     */
/* RETURNED VALUE:                                                     */
/*   For ports: pointer to data area of packet beyond header:          */
/*           <dest><source><opcode><space>                             */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/* WARNINGS:                                                           */
/*                                                                     */
/***********************************************************************/

BIT8 *SetUpRespHdr(MIO_HDR_TYPE  *p_resp_packet,BIT8 *ssap,BIT8 *dsap,BIT8 *opcode)
{

   BIT8 *p_resp_buf;

   p_resp_buf = (BIT8  *)DMA_MEM + p_resp_packet->data_start;

   Copy2(ssap, p_resp_buf);
   p_resp_buf += 2;
   Copy2(dsap, p_resp_buf);
   p_resp_buf += 2;
   p_resp_buf += PutAsciiParam(opcode,p_resp_buf);  /* allow for opcodes > 2 */
   *p_resp_buf = ' ';
   p_resp_buf++;

   return p_resp_buf;
}

/***********************************************************************/
/* END FUNCTION: SetUpRespHdr                                          */
/***********************************************************************/


/***********************************************************************/
/* FUNCTION: SendRespBuf                                               */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: Given a pointer and a length, this function will set up    */
/*           an output packet and put it on the output queue.          */
/*           If the output is for MIO it will copy it to an MIO        */
/*           packet and put it on the MIO output queue.                */
/*                                                                     */
/* RETURNED VALUE: none                                                */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*                                                                     */
/* FILE SCOPE STATICS USED:                                            */
/*                                                                     */
/* CALLS:                                                              */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/* WARNINGS:                                                           */
/*                                                                     */
/*                                                                     */
/***********************************************************************/


void SendRespBuf(MIO_HDR_TYPE  *p_resp_packet,U_INT16 msg_len)
{

   /* length = length of dsap,ssap,opcode,space plus length of parameters */
   p_resp_packet->data_length = msg_len;
   p_resp_packet->cmd = WRITE_DATA;
   p_resp_packet->cmd_mod = COMPLETE_MSG;

   {
      /* transfer packet to driver */
      INTERRUPTS_OFF;
         AppendPacket(p_resp_packet, Wr_Output_Q[p_resp_packet->comm_port]);
      INTERRUPTS_ON;

         switch (p_resp_packet->comm_port)
         {
         case DRTA_PORT:
         case DRTB_PORT:
            /* nothing needed */
            break;
         }
      }
}

/***********************************************************************/
/* END FUNCTION: SendRespBuf                                           */
/***********************************************************************/

/***********************************************************************/
/* FUNCTION: ReturnRespBuf                                             */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: This function returns the write buffer to the free queue.  */
/*                                                                     */
/* RETURNED VALUE: none                                                */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/* WARNINGS:                                                           */
/*                                                                     */
/***********************************************************************/

void ReturnRespBuf(MIO_HDR_TYPE  *p_resp_packet)
{
   /* transfer packet to free queue */
   AppendPacket(p_resp_packet, Wr_Free_Q);
}

/***********************************************************************/
/* END FUNCTION: ReturnRespBuf                                         */
/***********************************************************************/





/***********************************************************************/
/* FUNCTION: DoCmd                                                     */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: General routine to handle commands for setting and         */
/*             reading setpoint.                                       */
/*                                                                     */
/* RETURNED VALUE: none                                                */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*                                                                     */
/* FILE SCOPE STATICS USED:                                            */
/*                                                                     */
/* CALLS:                                                              */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/* WARNINGS: If DoCmdPreFunction fails, the DoCmdPostFunction will     */
/*      not be executed.                                               */
/*                                                                     */
/***********************************************************************/


INT16 DoCmd(CMD_TYPE *p_cmd, BIT8 *p_resp_parm, const METHCMD  *p_cmd_table)
{

U_INT16          length;
int              param_index;
UI_ERR           error;

   error = OK;
   length = 0;

   /* check for parameters */
   if ( p_cmd->parmv[0] == 0 )
   {
      CmdErrorHandler(p_cmd, 1, MISSING_PARAM);
      return NO_RESPONSE;
   }

   /* check if host wants to read setpoints */
   if ( p_cmd->parms[0] == '?' )
   /* read setpoints */
   {
      length = 0;

      /* run pre function before requesting setpoints */
      error = DoCmdPreFunction(p_cmd_table);
      if ((error == OK) || (error == IGNORE_SETPTS))
      {
         for( param_index = 0 ; param_index <= p_cmd_table->maxindex ; param_index++)
         {
            /* add ',' if not first parameter */
            if( param_index != 0 )
            {
               length += PutAsciiParam((BIT8 *)"," , p_resp_parm+length);
            }

   mLog("Do Cmd,param_index=%d   ",param_index);
            error = GetWkfileParam(p_resp_parm+length,p_cmd_table,param_index);

            if ( error == OK )
            {
               /* add length of new parameter */
   mLog("resp_parm:%s\n",p_resp_parm+length);
               length += StrLen(p_resp_parm+length);
            }
         }

         /* run post function after requesting setpoints */
         error = DoCmdPostFunction(p_cmd_table);
         if(error != OK)
         {
            CmdErrorHandler(p_cmd, 0, error);
         }

         return length;
      }
      else
      {
         CmdErrorHandler(p_cmd, 0, error);
         return NO_RESPONSE;
      }
   }

   else
   {
      /* run pre function before setting setpoints */
      error = DoCmdPreFunction(p_cmd_table);
      if(error == OK)
      {

         /* set parameters */
         for( param_index = 0 ; (param_index < p_cmd->parmv[0]) && (param_index <= p_cmd_table->maxindex) ;
               param_index++)
         {

            if( StrLen( &p_cmd->parms[p_cmd->parmv[param_index+1]]) != 0 )
            {
               error = OK;
               error = SetWkfileParam(&p_cmd->parms[p_cmd->parmv[param_index+1]],
                        p_cmd_table , param_index );
               if(error != OK)
               {
                  CmdErrorHandler(p_cmd, param_index+1, error);

                    /* IFSP IBSP IFPP IBPP C1NR C2NR KLUDGE */
                  if(error == COMMAND_ABORTED) break;

                    /* GCPO KLUDGE */
                  if(error == PARAM_ABORTED)
                  {  /* flag this param and the next one in error and skip the next one */
                      CmdErrorHandler(p_cmd, param_index+2, error);
                       /* incrementing the loop index inside the loop causes a parm skip */
                      param_index ++;
                  }
               }
            }
         }

         /* run post function after setting setpoints */
         error = DoCmdPostFunction(p_cmd_table);
         if(error != OK)
         {
            CmdErrorHandler(p_cmd, 0, error);
         }

         return NO_RESPONSE;
      }
      else
      {
         CmdErrorHandler(p_cmd, 0, error);
         return NO_RESPONSE;
      }
   }
}

/***********************************************************************/
/* END FUNCTION: DoCmd                                                 */
/***********************************************************************/




/***********************************************************************/
/* FUNCTION: DoCmdWithResponse                                         */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: General routine to handle commands for setting and         */
/*             reading setpoint.  without seting the cmd error log.    */
/*                                                                     */
/* commands using this will always generate a two parameter response   */
/*   return value 1 :   UI_ERR - the error number if any, OK otherwise */
/*   return value 2 :   PARM   - the parm that generated the error     */
/*                                                                     */
/* RETURNED VALUE: length of the response                              */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*                                                                     */
/* FILE SCOPE STATICS USED:                                            */
/*                                                                     */
/* CALLS:                                                              */
/*                                                                     */
/* LIMITATIONS:  setpoint execution (setting) will stop when           */
/*               the first error is encountered!                       */
/*                                                                     */
/*               the post function is silently executed, errors will   */
/*               not be reported if it fails.                          */
/*                                                                     */
/* WARNINGS: If DoCmdPreFunction fails, the DoCmdPostFunction will     */
/*      not be executed.                                               */
/*                                                                     */
/***********************************************************************/


INT16 DoCmdWithResponse(CMD_TYPE *p_cmd, BIT8 *p_resp_parm, const METHCMD  *p_cmd_table)
{

U_INT16           length;
int               param_index;
UI_ERR           error;



   error = OK;
   length = 0;

   /* check for parameters */
   if ( p_cmd->parmv[0] == 0 )
   {
      error = MISSING_PARAM;
      param_index = -2;
   }
   else if ( p_cmd->parms[0] == '?' )    /* check if host wants to read setpoints */
   {
      if( (error = DoCmdPreFunction(p_cmd_table)) == OK)
      {
         for( param_index = 0 ; param_index <= p_cmd_table->maxindex ; param_index++)
         {
            if ( param_index != 0 )    /* add ',' if not first parameter */
            {
               length += PutAsciiParam((BIT8 *)"," , p_resp_parm+length);
            }

            error = GetWkfileParam(p_resp_parm+length,p_cmd_table,param_index);

            if ( error == OK )
            {
               length += StrLen(p_resp_parm+length);     /* add length of new parameter */
            }
            else
            {
               break;  /* end processing of subsequent parameters */
            }
         }

         (void)DoCmdPostFunction(p_cmd_table);
      }
      else      /* pre command failed */
      {
          param_index = -2;
      }

      if (error != OK )
      {
          CmdErrorHandler(p_cmd, param_index, error);
          return NO_RESPONSE;
      }
   }
   else                          /* set parameters */
   {
      if( (error = DoCmdPreFunction(p_cmd_table)) == OK)
      {
         for( param_index = 0 ; (param_index < p_cmd->parmv[0]) && (param_index <= p_cmd_table->maxindex) ; param_index++)
         {
            if( StrLen( &p_cmd->parms[p_cmd->parmv[param_index+1]]) != 0 )
            {
               error = SetWkfileParam(&p_cmd->parms[p_cmd->parmv[param_index+1]], p_cmd_table , param_index );

               if(error != OK) break;  /* end processing of subsequent parameters */
            }
         }

         (void)DoCmdPostFunction(p_cmd_table);
      }
      else   /* pre function failed */
      {
         param_index = -2;
      }

      if ( error == OK )
      {
          param_index = -1;
      }

      /* format the setpt response */
      length  = 0;
      length += PutIntParam  ( (INT32)error,  p_resp_parm+length, 0 );
      length += PutAsciiParam((BIT8 *)"," ,  p_resp_parm+length    );
      length += PutIntParam  ( param_index+1,  p_resp_parm+length, 0 );

   }

   return length;
}

/***********************************************************************/
/* END FUNCTION: DoCmdWithResponse                                     */
/***********************************************************************/




/***********************************************************************/
/* FUNCTION: DoStatus                                                  */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: General routine to handle the status commands.   These     */
/*            commands do not need a parameter,  so they are ignored.  */
/*                                                                     */
/* RETURNED VALUE: none                                                */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*                                                                     */
/* FILE SCOPE STATICS USED:                                            */
/*                                                                     */
/* CALLS:                                                              */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/* WARNINGS: If DoCmdPreFunction fails, the DoCmdPostFunction will     */
/*      not be executed.                                               */
/*                                                                     */
/***********************************************************************/


INT16 DoStatus(CMD_TYPE *p_cmd, BIT8 *p_resp_parm, const METHCMD  *p_cmd_table)
{

U_INT16           length;
int               param_index;
UI_ERR           error;


   (void)p_cmd;

   error = OK;
   length = 0;

   /* run pre function before requesting setpoints */
   error = DoCmdPreFunction(p_cmd_table);
   if(error == OK)
   {

      /* read setpoints */
      for( param_index = 0 ; error == OK ; param_index++)
      {
         /* add ',' if not first parameter */
         if( param_index != 0 )
         {
            length += PutAsciiParam((BIT8 *)"," , p_resp_parm+length);
         }

         error = GetWkfileParam( p_resp_parm+length, p_cmd_table, param_index );
         if ( error == OK )
         {
            /* add length of new parameter */
            length += StrLen(p_resp_parm+length);
         }
         else
         {
            /* remove ',' if added */
            if( param_index != 0 )
            {
               length--;
            }
         }
      }
   }
   else
   {
      CmdErrorHandler(p_cmd, 0, error);
      return NO_RESPONSE;
   }

   /* run post function after requesting setpoints */
   error = DoCmdPostFunction(p_cmd_table);
   if(error != OK)
   {
      CmdErrorHandler(p_cmd, 0, error);
   }

   return length;
}

/***********************************************************************/
/* END FUNCTION: DoStatus                                              */
/***********************************************************************/


/***********************************************************************/
/* FUNCTION: GetMsg                                                    */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: Gets message from message buffer (Q0). Used with sampler.  */
/*                                                                     */
/* RETURNED VALUE: Returns pointer to command structure.  Points to    */
/*              null if no message is available.                       */
/*                                                                     */
/*                                                                     */
/* WARNINGS:   calling program should check for a return of null       */
/*                                                                     */
/***********************************************************************/

CMD_TYPE *GetMsg(BIT8  **p_get_buf)
{
CMD_TYPE *p_cmd_hdr;

   GetCmd(p_cmd_hdr,Q0_Cmd_Q);
   /* set up pointer to new msg */
   if(p_cmd_hdr)
   {
   *p_get_buf = p_cmd_hdr->parms;
   }
   return p_cmd_hdr;
}

/***********************************************************************/
/* END FUNCTION: GetMsg                                                */
/***********************************************************************/

/***********************************************************************/
/* FUNCTION: GetQ2Msg                                                  */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: Gets message from message buffer (Q2). Used with sampler.  */
/*                                                                     */
/* RETURNED VALUE: Returns pointer to command structure.  Points to    */
/*              null if no message is available.                       */
/*                                                                     */
/* WARNINGS:   calling program should check for a return of null       */
/*                                                                     */
/***********************************************************************/
CMD_TYPE *GetQ2Msg(BIT8  **p_get_buf)
{
CMD_TYPE *p_cmd_hdr;

   GetCmd(p_cmd_hdr,Q2_Cmd_Q);
   /* set up pointer to new msg */
   if(p_cmd_hdr)
   {
      *p_get_buf = p_cmd_hdr->parms;
   }
   return p_cmd_hdr;
}

/***********************************************************************/
/* END FUNCTION: GetMsgQ2                                              */
/***********************************************************************/

/***********************************************************************/
/* FUNCTION: GetQ3Msg                                                  */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: Gets message from message buffer (Q3). Used with sampler.  */
/*                                                                     */
/* RETURNED VALUE: Returns pointer to command structure.  Points to    */
/*              null if no message is available.                       */
/*                                                                     */
/* WARNINGS:   calling program should check for a return of null       */
/*                                                                     */
/***********************************************************************/
CMD_TYPE *GetQ3Msg(BIT8  **p_get_buf)
{
CMD_TYPE *p_cmd_hdr;

   GetCmd(p_cmd_hdr,Q3_Cmd_Q);
   /* set up pointer to new msg */
   if(p_cmd_hdr)
   {
      *p_get_buf = p_cmd_hdr->parms;
   }
   return p_cmd_hdr;
}

/***********************************************************************/
/* END FUNCTION: GetQ3Msg                                              */
/***********************************************************************/




/***********************************************************************/
/* FUNCTION: ReturnGetBuf                                              */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: The buffer obtained by GetMsg or GetQ2Msg is returned to   */
/*            queue of free packets.                                   */
/*                                                                     */
/* RETURNED VALUE:   None                                              */
/*                                                                     */
/*                                                                     */
/* WARNINGS:   ReturnGetBuf should always follow a successful GetMsg.  */
/*                                                                     */
/***********************************************************************/

void ReturnGetBuf(CMD_TYPE *p_cmd_hdr)
{
   AppendCmd(p_cmd_hdr,Free_Cmd_Q);
}

/***********************************************************************/
/* END FUNCTION: ReturnGetBuf                                          */
/***********************************************************************/


/***********************************************************************/
/* FUNCTION: AcquirePutBuf                                             */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: Acquires an outgoing buffer.                               */
/*                                                                     */
/* RETURNED VALUE: Returns pointer to a structure containing           */
/*          the address of the buffer. Also sets the address of        */
/*          the buffer in the location given.                          */
/*          The return value may be null if no buffers are available.  */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*                                                                     */
/* FILE SCOPE STATICS USED:                                            */
/*                                                                     */
/* CALLS:                                                              */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/* WARNINGS:   Although there should always be a buffer available,     */
/*           the calling program should check for a return of null     */
/*                                                                     */
/***********************************************************************/

MIO_HDR_TYPE  *AcquirePutBuf(BIT8 **p_put_buf)
{
MIO_HDR_TYPE  *p_mio_hdr;

   INTERRUPTS_OFF;
   if(Wr_Free_Q.num_entries > 2)  /* save one for host ports */
   {
      GetPacket(p_mio_hdr,Wr_Free_Q);
      if( p_mio_hdr )
      {
         *p_put_buf = (BIT8 *)DMA_MEM + p_mio_hdr->data_start;
      }
   }
   else
   {
       p_mio_hdr = NULL;
   }
   INTERRUPTS_ON;
   return p_mio_hdr;
}

/***********************************************************************/
/* END FUNCTION: AcquirePutBuf                                         */
/***********************************************************************/


/***********************************************************************/
/* FUNCTION: PutMsg                                                    */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: Sends buffer of data out port given.                       */
/*                                                                     */
/* RETURNED VALUE: None                                                */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*                                                                     */
/* FILE SCOPE STATICS USED:                                            */
/*                                                                     */
/* CALLS:                                                              */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/* WARNINGS:                                                           */
/*                                                                     */
/***********************************************************************/

void PutMsg(MIO_HDR_TYPE  *p_mio_hdr,U_INT16  port,U_INT16  length)
{
   p_mio_hdr->data_length = length;
   p_mio_hdr->cmd_mod = COMPLETE_MSG;
   p_mio_hdr->comm_port = (U_INT16)port;

   INTERRUPTS_OFF;
      AppendPacket(p_mio_hdr,Wr_Output_Q[(U_INT16)port]);
   INTERRUPTS_ON;

   switch (p_mio_hdr->comm_port)
   {
      case DRTA_PORT:
      case DRTB_PORT:
         /* nothing needed */
         break;
   }

}

/***********************************************************************/
/* END FUNCTION: PutMsg                                                */
/***********************************************************************/


/***********************************************************************/
/* FUNCTION: PathTableEntry                                            */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: Determines if the address is in the pass thru command      */
/*              path table and returns the entry number.               */
/*                                                                     */
/* RETURNED VALUE:                                                     */
/*        if in table:                                                 */
/*             index number                                            */
/*        if not in table:                                             */
/*             -1                                                      */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/***********************************************************************/

INT16  PathTableEntry(BIT8  *sap)
{
INT16 not_in_table,index;

   /* check if host sap is already in use */
   index = 0;
   not_in_table = FALSE;
   while( (not_in_table == FALSE) &&
              !StrNCmp( &(Com_Path[index].hdsap.char_hdsap[0]),sap, 2) )
   {
      index++;
      if(index >= NUM_PATHS)
      {
         not_in_table = TRUE;
      }
   }
   /* entry already in table so reject command */
   if(not_in_table == FALSE)
   {
      return  index;
   }
   else
   {
      return -1;
   }

}
/***********************************************************************/
/* END FUNCTION: PathTableEntry                                        */
/***********************************************************************/

/***********************************************************************/
/* FUNCTION: ExecCmds                                                  */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: Executes the command if one is available in command queue. */
/*                                                                     */
/* RETURNED VALUE: None                                                */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/***********************************************************************/

U_INT16      Cmd_Port;

void ExecCmds( CMD_QUEUE_TYPE *Cmd_Q,
        INT16 (*XXOpcodes)(CMD_TYPE *p_cmd,BIT8 *p_resp_parm,U_INT16 max_resp_len) )
{
CMD_TYPE *p_cmd;
MIO_HDR_TYPE    *p_resp_packet;
BIT8            *p_resp_parm;
INT16            parm_len;
U_INT16          max_resp_len;
BIT8            *p_resp_buf;
U_INT16          hdr_len;

   /* check if input message and if there is room for response */
   INTERRUPTS_OFF;
   if(Cmd_Q->num_entries != 0)
   {
      /* is the next command from the MIO port or HPIB or RS232 or INTERNAL? */
      /* REVISIT get comm_port for testing */
      Cmd_Port =  NextCmd_Port(*Cmd_Q);
      switch( NextCmd_Port(*Cmd_Q) )
      {
      case INTERNAL_BUFFER:
         /* Note: ExecuteWkfileCmds is used for building a workfile, only get */
         /*      here when installing workfile. */
         GetCmd(p_cmd, *Cmd_Q);
         INTERRUPTS_ON;

         /* Since installing workfile has no responses may use any address */
         /*     and length */
         max_resp_len = 25;  /* arbitrary */

         /* execute command */
         parm_len = XXOpcodes(p_cmd,Internal_Buffer.p_buffer,max_resp_len);

         /* there should be no response form commands */
         if(parm_len != NO_RESPONSE)
         {
            /* REVISIT  display for debugging */
            /* should not get here since now use ExecuteWkfileCmds for internal */
            DisplayErrors(MSG_TROUBLESHOOT,(INT32)Cmd_Port,Cmd_Q->head,
                                                      Cmd_Q->num_entries);
         }

         /* return cmd structure to queue */
         AppendCmd(p_cmd, Free_Cmd_Q);

         break;

      case DRTA_PORT:
      case DRTB_PORT:
      case DRTC_PORT:
         if(Wr_Free_Q.num_entries != 0)
         {

            pthread_mutex_lock(&Cmd_Q_Mut);
            GetCmdSafe(p_cmd, *Cmd_Q);      /* must have interrupts off */
            pthread_mutex_unlock(&Cmd_Q_Mut);
            mLog("get p_cmd from Cmd_Q\n");
            p_resp_packet = GetRespBuf();
            INTERRUPTS_ON;
            /* set up response buffer header and data area */
            p_resp_packet->comm_port = p_cmd->comm_port;
            p_resp_parm = SetUpRespHdr(p_resp_packet, p_cmd->ssap.char_ssap,
                   p_cmd->dsap.char_dsap, p_cmd->opcode.char_op);
            /* calculate how many bytes are already in the response */
            p_resp_buf = (BIT8  *)DMA_MEM + p_resp_packet->data_start;
            hdr_len = (U_INT16)( (U_INT32)p_resp_parm - (U_INT32)p_resp_buf );

            /* bytes remaining = max packet len - msg hdr - term seq(1) */
            max_resp_len = p_resp_packet->max_data_len - hdr_len - 1;

            /* execute command */
            parm_len = XXOpcodes(p_cmd,p_resp_parm,max_resp_len);

            /* return cmd structure to queue */
            /* REVISIT set comm_port to junk for testing */
            p_cmd->comm_port = 0x1234;
            Cmd_Port = INTERNAL_BUFFER;      /* For keyboard commands */
            AppendCmd(p_cmd, Free_Cmd_Q);


            /* send response packet or return it to free queue */
            if(parm_len==NO_RESPONSE)
            {
               ReturnRespBuf(p_resp_packet);
            }
            else
            {
//mLog("p_resp_packet->comm_port:%d p_resp_buf:%s\n",p_resp_packet->comm_port,p_resp_buf);
               SendRespBuf(p_resp_packet,hdr_len+parm_len);
            }
         }
         else
         {
            INTERRUPTS_ON;
         }
         break;
      default:
         /* error port not set correctly */
         INTERRUPTS_ON;
         /* REVISIT  display for debugging */
         DisplayErrors(MSG_TROUBLESHOOT,(INT32)Cmd_Port,Cmd_Q->head,
                                                   Cmd_Q->num_entries);
         break;

      } /* switch */
   }  /* if(Cmd_Q->num_entries != 0) */
   else
   {
      INTERRUPTS_ON;
   }
}

/***********************************************************************/
/* END FUNCTION: ExecCmds                                              */
/***********************************************************************/

/***********************************************************************/
/* FUNCTION: ExecWkfileCmds                                            */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: Executes the command if one is available in command queue. */
/*            Intended to be used to build a workfile.                 */
/*                                                                     */
/* RETURNED VALUE: None                                                */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/***********************************************************************/

void ExecWkfileCmds( CMD_TYPE *p_cmd,
                 INT16 (*XXOpcodes)(CMD_TYPE  *p_cmd,BIT8  *p_resp_parm,U_INT16 max_resp_len) )
{
  printf("call ExecWkfileCmds\n");
}

/***********************************************************************/
/* END FUNCTION: ExecWkfileCmds                                        */
/***********************************************************************/


/***********************************************************************/
/* FUNCTION: CmdsRemaining                                             */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: Goes through all command queues and returns the number     */
/*               of commands remaining in queues to be executed.       */
/*                                                                     */
/* RETURNED VALUE: Number of unprocessed commands queued up.           */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*                                                                     */
/* FILE SCOPE STATICS USED:                                            */
/*                                                                     */
/* CALLS:                                                              */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/* WARNINGS:                                                           */
/*                                                                     */
/***********************************************************************/

U_INT16  CmdsRemaining(void)
{
   U_INT16 num;
   num = 0;
   num += GC_Cmd_Q.num_entries;
   num += CC_Cmd_Q.num_entries;
   num += S1_Cmd_Q.num_entries;
   num += S2_Cmd_Q.num_entries;
   num += SP_Cmd_Q.num_entries;
   num += SS_Cmd_Q.num_entries;
   num += OV_Cmd_Q.num_entries;
   num += IX_Cmd_Q.num_entries;
   num += DX_Cmd_Q.num_entries;
   num += CX_Cmd_Q.num_entries;
   num += AX_Cmd_Q.num_entries;
   num += VX_Cmd_Q.num_entries;
   num += AS_Cmd_Q.num_entries;
   num += _0X_Cmd_Q.num_entries;
   num += DT_Cmd_Q.num_entries;
   num += TP_Cmd_Q.num_entries;

   return num;
}
/***********************************************************************/
/* END FUNCTION: CmdsRemaining                                         */
/***********************************************************************/

/***********************************************************************/
/* FUNCTION: ProcessCmds                                                  */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: This function will check all command queues and process    */
/*         up to one command from each queue.                          */
/*                                                                     */
/* RETURNED VALUE: Number of commands remaining to be processed.       */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*                                                                     */
/* FILE SCOPE STATICS USED:                                            */
/*                                                                     */
/* CALLS:                                                              */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/* WARNINGS:                                                           */
/*                                                                     */
/***********************************************************************/

U_INT16 ProcessCmds(void)
{
  /*
   GC_Cmds();
   CC_Cmds();
   S1_Cmds();
   S2_Cmds();
   SP_Cmds();
   SS_Cmds();
*/
   IQ_Cmds();
/*
   OV_Cmds();
   IX_Cmds();
   DX_Cmds();
   CX_Cmds();
   AX_Cmds();
   VX_Cmds();
   AS_Cmds();
   _0X_Cmds();
   PX_Cmds();
*/
   DT_Cmds();
//   TP_Cmds();
   return  CmdsRemaining();
}
/***********************************************************************/
/* END FUNCTION: Process_Cmds                                          */
/***********************************************************************/
